package ConCurrent;

import java.util.concurrent.Semaphore;

/** 使用 Semaphore
 * `Semaphore` 是一个计数信号量，可以用来限制同时访问某个资源的线程数量。我们可以通过创建多个 `Semaphore` 实例来实现线程的顺序执行。
 *
 *  写法和CountDownLatch相同，创建两个计数信号量，用于控制 AB 和 BC的顺序。
 *
 *  - 创建两个 `Semaphore` 实例 `semaphoreAB` 和 `semaphoreBC`，初始许可数为 0。
 * - 线程 A 在执行完毕后调用 `semaphoreAB.release()`，释放一个许可，通知线程 B 开始执行。
 * - 线程 B 在开始执行前调用 `semaphoreAB.acquire()`，等待线程 A 完成。
 * - 线程 B 在执行完毕后调用 `semaphoreBC.release()`，释放一个许可，通知线程 C 开始执行。
 * - 线程 C 在开始执行前调用 `semaphoreBC.acquire()`，等待线程 B 完成。
 */
public class ThreadFiFO2 {
    public static void main(String[] args) {
        // 创建两个 Semaphore，分别用于控制线程 B 和线程 C 的启动
        Semaphore semaphoreAB = new Semaphore(0);
        Semaphore semaphoreBC = new Semaphore(0);

        // 创建线程 A
        Thread threadA = new Thread(() -> {
            System.out.println("Thread A starts execution");
            try {
                Thread.sleep(1000); // 模拟线程 A 的执行时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread A finishes execution");
            semaphoreAB.release(); // 释放一个许可，通知线程 B 开始执行
        }, "ThreadA");

        // 创建线程 B
        Thread threadB = new Thread(() -> {
            try {
                semaphoreAB.acquire(); // 等待线程 A 完成
                System.out.println("Thread B starts execution");
                try {
                    Thread.sleep(1000); // 模拟线程 B 的执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread B finishes execution");
                semaphoreBC.release(); // 释放一个许可，通知线程 C 开始执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "ThreadB");

        // 创建线程 C
        Thread threadC = new Thread(() -> {
            try {
                semaphoreBC.acquire(); // 等待线程 B 完成
                System.out.println("Thread C starts execution");
                try {
                    Thread.sleep(1000); // 模拟线程 C 的执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread C finishes execution");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "ThreadC");

        // 启动线程
        threadA.start();
        threadB.start();
        threadC.start();
    }
}
